#include "BestQuoteData.h"
#include "core/comdefs.h"
#include <core/QbLogger.h>
#include <algorithm>
#include <chrono>
#include <QDebug>

#define BROKER_COUNT 6

void PRICE2::SetPrice(xQBBestPriceUnit_c& unit)
{
    strcpy(m_bp_status, unit.m_bp_status);
    strcpy(m_price_status, unit.m_price_status);
    strcpy(m_quotetype, unit.m_quotetype);
    strcpy(m_sPrice, unit.m_price);
    strcpy(m_yield_price, unit.m_yield);
    strcpy(m_clean_price, unit.m_clean_price);
    strcpy(m_sVolume, unit.m_volume);
    strcpy(m_description, unit.m_price_description);
    strcpy(m_interpret, unit.m_interpret);
    strcpy(m_exercise, unit.m_exercise);
	m_create_time = unit.m_create_time;
	m_time = unit.m_modify_time;
}

void PRICE2::SetPrice(PRICE2& price)
{
    strcpy(m_bp_status, price.m_bp_status);
    strcpy(m_price_status, price.m_price_status);
    strcpy(m_quotetype, price.m_quotetype);
    strcpy(m_sPrice, price.m_sPrice);
    strcpy(m_yield_price, price.m_yield_price);
    strcpy(m_clean_price, price.m_clean_price);
    strcpy(m_sVolume, price.m_sVolume);
    strcpy(m_description, price.m_description);
    strcpy(m_interpret, price.m_interpret);
    strcpy(m_exercise, price.m_exercise);
    m_create_time = price.m_create_time;
    m_time = price.m_time;
}

BestQuoteData::BestQuoteData()
    : m_pBondRptIndex(NULL)
	, m_sortKey(eSort_time)
    , m_sortDirection(false)
{
}

BestQuoteData::~BestQuoteData()
{
}

BestQuoteData& BestQuoteData::GetInstance()
{
	static BestQuoteData bqData;
	return bqData;
}

BestQuoteMiniFilter& BestQuoteData::GetFilter() {
	return m_filter;
}

void BestQuoteData::InitData()
{
    if (!m_pBondRptIndex)
    {
        int32_t nBondCount = 0;

        m_pBondRptIndex = (int32_t**)malloc(sizeof(int32_t*)*BROKER_COUNT);
        for (int32_t i = 0; i < BROKER_COUNT; ++i)
        {
            m_pBondRptIndex[i] = (int32_t*)malloc(sizeof(int32_t)*nBondCount);

            for (int32_t j = 0; j < nBondCount; ++j)
            {
                m_pBondRptIndex[i][j] = -1;
            }
        }
    }
}

void BestQuoteData::UpdateData(void* pData)
{
	auto T0 = std::chrono::system_clock::now();

    BestQuoteProcessData* pd = (BestQuoteProcessData*)pData;
    QB_CHECK_RETURN_VOID1(pd && m_pBondRptIndex);

    log_debug("%s m_index.size() = %d", __FUNCTION__, m_index.size());

    int32_t nBondCount = 0;

    for (uint32_t i = 0; i < pd->count; i++)
    {
        if (pd->pbib[i].brokerId < 1 || pd->pbib[i].brokerId > BROKER_COUNT || (int)pd->pbib[i].bondIndex >= nBondCount)
        {
            continue;
        }

        BondIndexBroker bk;
        bk.brokerId = pd->pbib[i].brokerId;
        bk.bondIndex = pd->pbib[i].bondIndex;

        uint32_t brokerIndex = bk.brokerId-1;
        uint32_t bondIndex = bk.bondIndex;

        if (-1 == m_pBondRptIndex[brokerIndex][bondIndex])
        {
            m_quotedata.push_back(pd->prpt[i]);
            m_pBondRptIndex[brokerIndex][bondIndex] = bk.reportIndex = m_quotedata.size() - 1;
            m_index.push_back(bk);
			if(IsPassCondition(bk))
				m_result.push_back(m_index.size() - 1);
        }
        else
        {
            int32_t rptIndex = m_pBondRptIndex[brokerIndex][bondIndex];
            REPORT2& rpt = m_quotedata[rptIndex];
            if (rpt.m_dwVersion > pd->prpt[i].m_dwVersion)
            {
                continue;
            }

            rpt.m_dwVersion = pd->prpt[i].m_dwVersion;
            rpt.m_time = pd->prpt[i].m_time;

            if (pd->prpt[i].m_dir == 1)
            {
                rpt.m_bidinfo.SetPrice(pd->prpt[i].m_bidinfo);
            }
            else
            {
                rpt.m_askinfo.SetPrice(pd->prpt[i].m_askinfo);
            }

			std::vector<BondIndexBroker>::iterator it = std::find(m_index.begin(), m_index.end(), bk);
			int idindex = -1;
			if (it != m_index.end())
			{
				idindex = it - m_index.begin();
				bk.reportIndex = idindex;
			}
			else
			{
				Q_ASSERT(0);
			}
			if (IsPassCondition(bk))
			{
				if (std::find(m_result.begin(), m_result.end(), idindex) == m_result.end())
					m_result.push_back(idindex);
			}
			else
			{
				std::vector<int>::iterator itr = std::find(m_result.begin(), m_result.end(), idindex);
				if (itr != m_result.end())
					m_result.erase(itr);
			}
        }
    }
	auto T1 = std::chrono::system_clock::now();
	log_debug("%s BestQuoteData::UpdateData total %d records, cost %dms", __FUNCTION__, m_index.size(), std::chrono::duration_cast<std::chrono::milliseconds>(T1 - T0).count());
}

void BestQuoteData::UnInitData()
{
    if (m_pBondRptIndex)
    {
        for (int32_t i = 0; i < BROKER_COUNT; ++i)
        {
            free(m_pBondRptIndex[i]);
        }

        free(m_pBondRptIndex);
        m_pBondRptIndex = NULL;
    }
}

void BestQuoteData::ReloadData()
{
	m_result.clear();
	int sz = (int)m_index.size();
	if (sz <= 0)return;

	if (m_filter.m_nBrokerId == 0)
	{
		for (int i = 0; i < sz; i++)
		{
			m_result.push_back(i);
		}
		return;
	}
	else
	{
		for (int i = 0; i < sz; i++)
		{
			BondIndexBroker& bk = m_index[i];
			if(IsPassCondition(bk))
				m_result.push_back(i);
		}
		return;
	}
}

void BestQuoteData::Sort()
{
	class compare_code
	{
	public:
        compare_code(BestQuoteData* pThis)
            : m_pThis(pThis){}
		bool operator() (int i1, int i2)
		{
			BondIndexBroker& bk1 = m_pThis->m_index[i1];
			BondIndexBroker& bk2 = m_pThis->m_index[i2];

            return false;
		}
	private:
		BestQuoteData* m_pThis;
    }sort_compare_code(this);

	class compare_name
	{
	public:
        compare_name(BestQuoteData* pThis)
            : m_pThis(pThis) {}
		bool operator() (int i1, int i2)
		{
			BondIndexBroker& bk1 = m_pThis->m_index[i1];
			BondIndexBroker& bk2 = m_pThis->m_index[i2];

            return true;
		}
	private:
		BestQuoteData* m_pThis;
    }sort_compare_name(this);

	class compare_time
	{
	public:
		compare_time(BestQuoteData* pThis) :m_pThis(pThis) {}
		bool operator() (int i1, int i2)
		{
			BondIndexBroker& bk1 = m_pThis->m_index[i1];
			BondIndexBroker& bk2 = m_pThis->m_index[i2];

			REPORT2& rpt1 = m_pThis->m_quotedata[bk1.reportIndex];
			REPORT2& rpt2 = m_pThis->m_quotedata[bk2.reportIndex];

			return rpt1.m_time < rpt2.m_time;
		}
	private:
		BestQuoteData* m_pThis;
	}sort_compare_time(this);

	switch (m_sortKey)
	{
	case eSort_Code:
		if (m_sortDirection)
			std::sort(m_result.begin(), m_result.end(), sort_compare_code);
		else
			std::sort(m_result.rbegin(), m_result.rend(), sort_compare_code);
		break;
	case eSort_Name:
		if (m_sortDirection)
			std::sort(m_result.begin(), m_result.end(), sort_compare_name);
		else
			std::sort(m_result.rbegin(), m_result.rend(), sort_compare_name);
		break;
	case eSort_time:
		if(m_sortDirection)
			std::sort(m_result.begin(), m_result.end(), sort_compare_time);
		else
			std::sort(m_result.rbegin(), m_result.rend(), sort_compare_time);
		break;
	default:
		break;
	}
}


bool BestQuoteData::IsPassCondition(const BondIndexBroker& bk)
{
	if (m_filter.m_nBrokerId > 0 && m_filter.m_nBrokerId != bk.brokerId)return false;
	if (bk.reportIndex < 0 || bk.reportIndex >= m_quotedata.size())
	{
		return false;
	}
	const REPORT2& rpt = m_quotedata[bk.reportIndex];
	if (m_filter.m_bValidPrice && !rpt.IsPriceStatusValid())return false;
	return true;
}
